Open In Colab

Table de contenido

  • 1   Proyecto EDA, agrupaciones y caracteristicas de vacunados post COVID
  • 2  Contexto
    • 2.1  Pregunta SMART
    • 2.2  Objetivo
    • 2.3  Descripción de los campos
  • 3  Análisis exploratorio
    • 3.1  Análisis de estructura de campos y Limpieza de datos
      • 3.1.1  Estandarizacion de Fecha
      • 3.1.2  Revisión de valores perdidos
      • 3.1.3  Ajuste de tipos de variables
      • 3.1.3  Normalización de Departamento y Municipio
    • 3.2  Análisis de variables categóricas
      • 3.2.1  Variable Sexo
      • 3.2.2  Variable Municipio Aplicación
      • 3.2.3  Variable Biológico
      • 3.2.4  Variable Número de dosis
      • 3.2.5  Variable comorbilidades
      • 3.2.6  Variable Desenlaces Clinicos
      • 3.2.7  Variable Afiliacion y Regimen
    • 3.4  Analisis de outliers
      • 3.4.2  Conclusiones Outliers
  • 4  Limpieza de datos
    • 4.3  Estandarización
    • 4.4  Imputación
  • 5  Analisis Estadistico
In [1]:
%%capture
#!pip install bayesian-optimization
In [4]:
%%capture
import math


import seaborn as sns
import pandas as pd
import numpy as np
import random
import altair as alt
%matplotlib inline
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.subplots as sp
import matplotlib.gridspec as gridspec
from plotly.subplots import make_subplots
import plotly.graph_objects as go

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Ridge, Lasso, LogisticRegression #modelamiento
from sklearn.cluster import KMeans
from sklearn.mixture import GaussianMixture
from sklearn.feature_selection import SelectFromModel
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis
from sklearn.decomposition import PCA
from IPython.display import display
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer #missing value imputation
from sklearn.svm import SVC
# from bayes_opt import BayesianOptimization
from sklearn.metrics import roc_auc_score,roc_curve
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.neural_network import MLPClassifier

# import warnings filter
from warnings import simplefilter
# ignore all future warnings
simplefilter(action='ignore', category=FutureWarning)
simplefilter(action='ignore', category=UserWarning)

pd.set_option('display.float_format', '{:,.2f}'.format)
np.seterr(divide = 'ignore')

# Supress warnings
import warnings
warnings.filterwarnings("ignore")
In [5]:
import matplotlib.ticker as mtick  ## función para formatear en visualizaciones
from scipy.stats import skew, kurtosis  ## funciones estadísticas
from sklearn.impute import KNNImputer
from sklearn.preprocessing import LabelEncoder


import matplotlib.ticker as mtick  ## función para formatear en visualizaciones
from scipy.stats import norm ## distribución normal
from scipy.stats import poisson ## distribución Poisson
from scipy.stats import t ## distribución t
from scipy.stats import f ## distribución F
from scipy.stats import ttest_1samp  ## Prueba t una población
from scipy.stats import ttest_ind ## Prueba t comparación medias
from scipy.stats import shapiro ## Prueba normalidad Shapiro-Wilks
from scipy.stats import anderson ## Prueba normalidad Anderson-Darling
from scipy.stats import levene ## Prueba homogeneidad de varianzas Levene
from scipy.stats import mannwhitneyu ## Prueba Mann-Whitney-Wilcoxon (comparación dos poblaciones)
from scipy.stats import f_oneway ## Prueba ANOVA de una vía
from scipy.stats import chi2_contingency ## Prueba chi cuadrado de Pearson
from scipy.stats import pearsonr ## Coeficiente de correlación de Pearson con prueba
import statsmodels.stats as sm  ## estadísticas
import statsmodels.api as sm1  ## estadísticas
from statsmodels.graphics.gofplots import qqplot ## Gráfico QQ plot

Contexo¶

La pandemia de COVID-19 ha sido un reto sin precedentes para la salud pública global. A nivel mundial se han reportado “más de 767 millones de casos confirmados y más de 6,9 millones de muertes” hasta junio de 2023. La región de las Américas ha sido una de las más golpeadas con el 43% de las defunciones reportadas globalmente y más de 2.9 millones de defunciones hasta dicha fecha.

La Organización Mundial de la Salud (OMS) ha resaltado la necesidad de contar con estudios post introducción de las vacunas contra COVID-19 en condiciones reales que capten las diferencias en la epidemiología de la enfermedad a nivel subnacional y en las variaciones programáticas de la implementación de las estrategias y políticas de vacunación.

En Colombia la vacunación contra COVID-19 inició en febrero de 2021 dirigida inicialmente a grupos de riesgo y paulatinamente a la población general.

Descripcion Dataset¶

Se tomo una muestra del conjunto de datos original, esta muestra contiene la información de 500.000 individuos de 4 ciudades de Colombia que recibieron al menos una dosis de la vacuna contra COVID-19, además se incluye información del sexo, la edad, el municipio en donde se vacuno, las fechas de cuando se aplicó la vacuna, también si la persona tiene alguna comorbilidad e información referente a los 3 desenlaces que se evalúan (confirmado, hospitalizado, fallecido).

Pregunta SMART¶

¿Existen diferencias significativas entre los individuos vacunados contra COVID-19 en 4 ciudades colombianas durante el periodo de 2021 a 2022 y sus desenlaces?

Specific: Se quiere saber si existen diferencias entre las personas que se vacunaron en las 4 ciudades colombianas.

Measurable: Se mide con pruebas estadísticas.

Action – oriented: Alcanzable con la información disponible y se motiva a realizar la investigación en otras ciudades o países.

Relevant: Se contribuye a la investigación con relación a las vacunas del COVID.

Time – bound: Se pretende estudiar en un plazo de 1 año.

Objetivo¶

evaluar si existen diferencias significativas en la base de datos que nos puedan indicar cómo se comportan los individuos vacunados teniendo en cuenta las diferentes variables que se incluyen en la bd

Descripción de los campos¶

Cada fila contiene la información de una persona vacunada, esta puede aparecer hasta máximo 4 veces. Esto se debe a que la persona puede tener aplicadas 4 distintas dosis (primera dosis, segunda dosis, primer refuerzo y segundo refuerzo), a continuación, se describen las variables del dataset:

  • PersonaBasicaID: Se refiere al identificador de la persona vacunada, está totalmente anonimizado.
  • Sexo: El sexo de la persona vacuna.
  • Edad: Edad de la persona vacunada al momento de recibir la dosis.
  • FechaNacimiento: Corresponde a la fecha de nacimiento del individuo vacunado.
  • DepartamentoAplicacion: Departamento en donde recibo la dosis el individuo vacunado.
  • MunicipioAplicacion: Municipio en donde recibo la dosis el individuo vacunado.
  • Biológico: El biológico que se le aplico a la persona vacunada en cada una de las dosis.
  • FechaApliacion: Fecha cuando recibió la correspondiente dosis de la vacuna.
  • NumDosis: Indica cual dosis le fue suministrada a la persona vacunada.
  • CAC_VIH: Indica 1 si la persona vacunada tiene VIH, en caso contrario 0.
  • CAC_HTA: Indica 1 si la persona vacunada tiene Hipertensión Arterial, en caso contrario 0.
  • CAC_Diabetes: Indica 1 si la persona vacunada tiene Diabetes, en caso contrario 0.
  • CAC_PEH: Indica 1 si la persona vacunada tiene Enfermedades huérfanas, en caso contrario 0.
  • CAC_Cancer: Indica 1 si la persona vacunada tiene Cáncer, en caso contrario 0.
  • CAC_Artritis: Indica 1 si la persona vacunada tiene Artritis, en caso contrario 0.
  • Confirmado: Indica 1 si el individuo vacunado resulto positivo para COVID-19, en caso contrario 0.
  • FechaInicioSintomas: Es la fecha en la que el individuo resulto positivo.
  • ServicioMayorComplejidad: Indica 1 si la persona requirió internación en una entidad hospitalaria, 0 en caso contrario.
  • FechaIngresoServicioMayorComplejidad: Fecha en la que la persona fue internada en una entidad hospitalaria.
  • NDEstadoVital: Indica 1 si la persona falleció a causa del COVID-19, 0 en caso contrario.
  • NDFechaDefuncion: Fecha en la que la persona falleció por COVID-19.
  • EstadoAfiliacion: Es el estado de afiliación del individuo vacunado al Sistema General de Seguridad Social en Salud.
  • Regimen: Es el régimen del individuo vacunado.

Análisis exploratorio¶

Empezaremos por revisar la estructura del dataset, la consistencia entre los datos y que tengan el formato adecuado.

Análisis de estructura de campos y Limpieza de datos¶

In [6]:
#Seccion 3.1
In [62]:
url = "https://media.githubusercontent.com/media/carlosjara/PRY_EDA_ICESI/main/data/Muestra.csv"
df = pd.read_csv(url, sep="|")
df.shape
Out[62]:
(1134483, 23)

Los datos cuentan con 1134483 observaciones (de 500000 personas - que pueden tener mas de una dosis) y 23 columnas

In [63]:
df.head()
Out[63]:
PersonaBasicaID Sexo Edad FechaNacimiento DepartamentoAplicacion MunicipioAplicacion Biológico FechaApliacion NumDosis CAC_VIH ... CAC_Cancer CAC_Artritis Confirmado FechaInicioSintomas ServicioMayorComplejidad FechaIngresoServicioMayorComplejidad NDEstadoVital NDFechaDefuncion EstadoAfiliacion Regimen
0 11638609 MASCULINO 39 19,840,118.00 05 - Antioquia 05001 - Medellín JANSSEN 20220212 0 0 ... 0 0 1 20210618 Ninguno 19000101 VIVO 19000101 ACTIVO CONTRIBUTIVO
1 29692489 FEMENINO 89 19,331,110.00 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 20220224 -1 0 ... 0 0 1 19000101 Ninguno 20210428 VIVO 19000101 ACTIVO CONTRIBUTIVO
2 29692489 FEMENINO 89 19,331,110.00 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 20210707 2 0 ... 0 0 1 19000101 Ninguno 20210428 VIVO 19000101 ACTIVO CONTRIBUTIVO
3 29692489 FEMENINO 89 19,331,110.00 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 20210314 1 0 ... 0 0 1 19000101 Ninguno 20210428 VIVO 19000101 ACTIVO CONTRIBUTIVO
4 8402648 FEMENINO 75 19,470,920.00 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 20210625 1 0 ... 0 0 0 19000101 Ninguno 19000101 VIVO 19000101 ACTIVO SUBSIDIADO

5 rows × 23 columns

Estandarizacion de Fecha¶

In [64]:
# Seccion 3.1.1
In [65]:
#Vamos dejar el mismor formato de fecha para las columnas correspondientes
columnas = ['FechaNacimiento','FechaInicioSintomas','FechaApliacion','FechaIngresoServicioMayorComplejidad','NDFechaDefuncion']
In [66]:
#usaremos la funcion to_datetime para dar un formato estandarizado
class FechaTransformer:
    def __init__(self, date_columns):
        self.date_columns = date_columns

    def transform_dates(self, df):
        for col in self.date_columns:
            df[col] = pd.to_datetime(df[col], format='%Y%m%d', errors='coerce')
        return df
In [67]:
columnas = ['FechaNacimiento','FechaInicioSintomas','FechaApliacion','FechaIngresoServicioMayorComplejidad','NDFechaDefuncion']
transformer = FechaTransformer(columnas)
df = transformer.transform_dates(df)

Ver Codigo sin usar clase transform

In [68]:
df.head()
Out[68]:
PersonaBasicaID Sexo Edad FechaNacimiento DepartamentoAplicacion MunicipioAplicacion Biológico FechaApliacion NumDosis CAC_VIH ... CAC_Cancer CAC_Artritis Confirmado FechaInicioSintomas ServicioMayorComplejidad FechaIngresoServicioMayorComplejidad NDEstadoVital NDFechaDefuncion EstadoAfiliacion Regimen
0 11638609 MASCULINO 39 1984-01-18 05 - Antioquia 05001 - Medellín JANSSEN 2022-02-12 0 0 ... 0 0 1 2021-06-18 Ninguno 1900-01-01 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO
1 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2022-02-24 -1 0 ... 0 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO
2 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-07-07 2 0 ... 0 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO
3 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-03-14 1 0 ... 0 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO
4 8402648 FEMENINO 75 1947-09-20 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-06-25 1 0 ... 0 0 0 1900-01-01 Ninguno 1900-01-01 VIVO 1900-01-01 ACTIVO SUBSIDIADO

5 rows × 23 columns

In [69]:
# Fin seccion 3.1.1

Revisión de valores perdidos¶

In [70]:
# Seccion 3.1.2
# importante mencionar que en secciones posteriores se hará el tratamiento de los datos
In [71]:
Value_count = df.isna().sum()
Value_Count_Mayor = Value_count[Value_count > 0]
print(f'Resumen:\r\n',Value_Count_Mayor)
Resumen:
 Sexo               522
FechaNacimiento     68
dtype: int64

Se puede ver que hay datos vacíos, para la variable FechaNacimiento y por tanto Edad de aplicacion, para la variable Sexo. En el proceso de limpieza se decidirá qué hacer con estas observaciones.

Valores perdidos variable Fecha Nacimiento¶

In [72]:
df['FechaNacimiento'].isna().sum()
Out[72]:
68
In [73]:
#Vamos a calcular la fecha promeido de nacimiento, para imputar
fecha_promedio = pd.to_datetime(df['FechaNacimiento'], errors='coerce').mean()
df['FechaNacimiento'].fillna(fecha_promedio, inplace=True)
In [74]:
#Calculamos la edad teniendo en cuenta la fecha de aplicacion
df['EdadAplicacion'] = (df['FechaApliacion'] - df['FechaNacimiento']).astype('<m8[Y]').astype('int64')
In [75]:
df.head()
Out[75]:
PersonaBasicaID Sexo Edad FechaNacimiento DepartamentoAplicacion MunicipioAplicacion Biológico FechaApliacion NumDosis CAC_VIH ... CAC_Artritis Confirmado FechaInicioSintomas ServicioMayorComplejidad FechaIngresoServicioMayorComplejidad NDEstadoVital NDFechaDefuncion EstadoAfiliacion Regimen EdadAplicacion
0 11638609 MASCULINO 39 1984-01-18 05 - Antioquia 05001 - Medellín JANSSEN 2022-02-12 0 0 ... 0 1 2021-06-18 Ninguno 1900-01-01 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO 38
1 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2022-02-24 -1 0 ... 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO 88
2 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-07-07 2 0 ... 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO 87
3 29692489 FEMENINO 89 1933-11-10 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-03-14 1 0 ... 0 1 1900-01-01 Ninguno 2021-04-28 VIVO 1900-01-01 ACTIVO CONTRIBUTIVO 87
4 8402648 FEMENINO 75 1947-09-20 11 - Bogotá, D.C. 11001 - Bogotá, D.C. SINOVAC 2021-06-25 1 0 ... 0 0 1900-01-01 Ninguno 1900-01-01 VIVO 1900-01-01 ACTIVO SUBSIDIADO 73

5 rows × 24 columns

La estructura de las columnas de fecha, se estandarizan para un mismo formato, teniendo en cuenta los nulos en la fecha de aplicacion, se actualiza la columna Edad por Edad de aplicacion que toma el valor promedio de nacimiento para imputar.

In [76]:
fig, ax = plt.subplots(figsize=(6,4))

# Create boxplots for 'EdadAplicacion' and 'EdadCalculada'
boxplot1 = ax.boxplot(df['EdadAplicacion'], positions=[1], patch_artist=True, boxprops=dict(facecolor='blue'))
boxplot2 = ax.boxplot(df['Edad'], positions=[2], patch_artist=True, boxprops=dict(facecolor='red'))

# Customize labels for the boxplots
ax.set_xticks([1, 2])
ax.set_xticklabels(['Edad Calculada', 'Edad Cargada'])

# Add legend manually
legend_labels = ['Edad Calculada', 'Edad Cargada']
colors = ['blue', 'red']
legend_patches = [plt.Rectangle((0, 0), 1, 1, color=color) for color in colors]
ax.legend(legend_patches, legend_labels)

# Add labels and title
ax.set_xlabel('Edad')
ax.set_title('Edad de cargada y Edad Calculada')

# Show the plot
plt.show()
In [77]:
df['EdadAplicacion'].describe()
Out[77]:
count   1,134,483.00
mean           43.49
std            19.99
min             1.00
25%            28.00
50%            42.00
75%            59.00
max           121.00
Name: EdadAplicacion, dtype: float64
In [78]:
# Crear los grupos de edad
bins = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]
labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80-89', '90-99', '100+']
df['GrupoEdad'] = pd.cut(df['EdadAplicacion'], bins=bins, labels=labels, right=False)

# Contar la cantidad de observaciones en cada grupo de edad
edad_counts = df['GrupoEdad'].value_counts().sort_index()

# Generar un gráfico de barras
plt.figure(figsize=(10, 6))
edad_counts.plot(kind='bar', color='skyblue')
plt.title('Distribución de Edades en Grupos de 10 Años')
plt.xlabel('Grupo de Edad')
plt.ylabel('Cantidad de Personas')
plt.xticks(rotation=45)
plt.show()

Valores perdidos variable SEXO¶

In [79]:
df['Sexo'].isna().sum()
# sera necesario hacer label enconding para imputacion con knn
Out[79]:
522
In [80]:
(df.value_counts('Sexo',normalize=True)*100).round(2).astype(str)+'%'
Out[80]:
Sexo
FEMENINO       54.51%
MASCULINO      45.46%
NO DEFINIDO     0.03%
INDEFINIDO       0.0%
dtype: object
In [81]:
df_form = df['Sexo'].value_counts(normalize=True).rename('Proportion').reset_index()
df_form.rename(columns={'index':'Sexo','Proportion':'Porcentaje'},inplace=True)
df_form.Porcentaje=np.round(df_form.Porcentaje * 100,decimals=2)
df_form.Sexo = df_form.Sexo
In [82]:
sns.set(style="whitegrid")
plt.figure(figsize=(8, 6))
ax = sns.barplot(x='Sexo', y='Porcentaje', data=df_form, palette='viridis')
plt.title('Distribución de Sexo')
plt.xlabel('Sexo')
plt.ylabel('Porcentaje')
plt.ylim(0, 70)

for p in ax.patches:
    ax.annotate(f'{p.get_height():.2f}%', (p.get_x() + p.get_width() / 2., p.get_height()), ha='center', va='center', fontsize=12, color='black', xytext=(0, 5), textcoords='offset points')
plt.show()
In [83]:
Value_count = df.isna().sum()
Value_Count_Mayor = Value_count[Value_count > 0]
print(f'Resumen:\r\n',Value_Count_Mayor)
Resumen:
 Sexo         522
GrupoEdad      3
dtype: int64
In [84]:
df['Sexo'].unique()
Out[84]:
array(['MASCULINO', 'FEMENINO', nan, 'NO DEFINIDO', 'INDEFINIDO'],
      dtype=object)
In [85]:
# Fin seccion 3.1.2

Ajuste de tipos de variables¶

In [86]:
#Seccion 3.1.3
In [87]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1134483 entries, 0 to 1134482
Data columns (total 25 columns):
 #   Column                                Non-Null Count    Dtype         
---  ------                                --------------    -----         
 0   PersonaBasicaID                       1134483 non-null  int64         
 1   Sexo                                  1133961 non-null  object        
 2   Edad                                  1134483 non-null  int64         
 3   FechaNacimiento                       1134483 non-null  datetime64[ns]
 4   DepartamentoAplicacion                1134483 non-null  object        
 5   MunicipioAplicacion                   1134483 non-null  object        
 6   Biológico                             1134483 non-null  object        
 7   FechaApliacion                        1134483 non-null  datetime64[ns]
 8   NumDosis                              1134483 non-null  int64         
 9   CAC_VIH                               1134483 non-null  int64         
 10  CAC_HTA                               1134483 non-null  int64         
 11  CAC_Diabetes                          1134483 non-null  int64         
 12  CAC_PEH                               1134483 non-null  int64         
 13  CAC_Cancer                            1134483 non-null  int64         
 14  CAC_Artritis                          1134483 non-null  int64         
 15  Confirmado                            1134483 non-null  int64         
 16  FechaInicioSintomas                   1134483 non-null  datetime64[ns]
 17  ServicioMayorComplejidad              1134483 non-null  object        
 18  FechaIngresoServicioMayorComplejidad  1134483 non-null  datetime64[ns]
 19  NDEstadoVital                         1134483 non-null  object        
 20  NDFechaDefuncion                      1134483 non-null  datetime64[ns]
 21  EstadoAfiliacion                      1134483 non-null  object        
 22  Regimen                               1134483 non-null  object        
 23  EdadAplicacion                        1134483 non-null  int64         
 24  GrupoEdad                             1134480 non-null  category      
dtypes: category(1), datetime64[ns](5), int64(11), object(8)
memory usage: 208.8+ MB
In [88]:
#df['CAC_Artritis'] = df['CAC_Artritis'].astype('object')
#df['CAC_VIH'] = df['CAC_VIH'].astype('object')
#df['CAC_HTA'] = df['CAC_HTA'].astype('object')
#df['CAC_Diabetes'] = df['CAC_Diabetes'].astype('object')
#df['CAC_PEH'] = df['CAC_PEH'].astype('object')
#df['CAC_Cancer'] = df['CAC_Cancer'].astype('object')

en esta seccion podemos corregir valores por su estructura y calcular valores basados en reemplazo de fechas por su media (Edad de aplicacion), en secciones posteriores se hará el tratamiento a demas variables

In [89]:
# Fin seccion 3.1.3

Normalizacion de Departamento y Municipio¶

Se busca mantener estructura de campos normalizado para uso adecuado de tipos y busquedas, en este caso las columnas DepartamentoAplicacion y MunicipioAplicacion pueden ser dividios.

In [90]:
df[['CodigoDepartamento', 'DescripcionDepartamento']] = df['DepartamentoAplicacion'].str.split(' - ', 1, expand=True)
df[['CodigoMunicipio', 'DescripcionMunicipio']] = df['MunicipioAplicacion'].str.split(' - ', 1, expand=True)
#df.drop(columns=['DepartamentoAplicacion', 'MunicipioAplicacion'], inplace=True)
columnas_numericas = ['CodigoDepartamento', 'CodigoMunicipio']
df[columnas_numericas] = df[columnas_numericas].astype('int64')
In [91]:
df.dtypes
Out[91]:
PersonaBasicaID                                  int64
Sexo                                            object
Edad                                             int64
FechaNacimiento                         datetime64[ns]
DepartamentoAplicacion                          object
MunicipioAplicacion                             object
Biológico                                       object
FechaApliacion                          datetime64[ns]
NumDosis                                         int64
CAC_VIH                                          int64
CAC_HTA                                          int64
CAC_Diabetes                                     int64
CAC_PEH                                          int64
CAC_Cancer                                       int64
CAC_Artritis                                     int64
Confirmado                                       int64
FechaInicioSintomas                     datetime64[ns]
ServicioMayorComplejidad                        object
FechaIngresoServicioMayorComplejidad    datetime64[ns]
NDEstadoVital                                   object
NDFechaDefuncion                        datetime64[ns]
EstadoAfiliacion                                object
Regimen                                         object
EdadAplicacion                                   int64
GrupoEdad                                     category
CodigoDepartamento                               int64
DescripcionDepartamento                         object
CodigoMunicipio                                  int64
DescripcionMunicipio                            object
dtype: object
In [92]:
#seccion 3.1.4
In [93]:
# Fin seccion 3.1.4
In [94]:
# Fin seccion 3.1

Análisis de variables categóricas¶

Según la descripción de los campos, las siguientes variables son categoricas: Sexo, DepartamentoAplicacion, MunicipioAplicacion, Biológico, NumDosis, CAC_VIH, CAC_HTA, CAC_Diabetes, CAC_PEH, CAC_Cancer, CAC_Artritis, CAC_Artritis, Confirmado, ServicioMayorComplejidad, NDEstadoVital, EstadoAfiliacion, Regimen.

Vamos a ver con qué tipo de dato se encuentran actualmente:

Análisis de estructura de campos y Limpieza de datos

In [96]:
df1 = df[['PersonaBasicaID', 'Sexo', 'Edad', 'NumDosis', 'CAC_VIH', 'CAC_HTA', 'CAC_Diabetes',
       'CAC_PEH', 'CAC_Cancer', 'CAC_Artritis', 'Confirmado', 'ServicioMayorComplejidad', 'NDEstadoVital','FechaNacimiento']]

df['ServicioMayorComplejidad'] = np.where(
                        df['FechaIngresoServicioMayorComplejidad'] == pd.Timestamp('1900-01-01'),
                        'No' , 'Hospitalizado')

df1["Confirmado"] = np.where(df1['Confirmado']== 'Positivo',1,0)
df1["Confirmado"]= df1["Confirmado"].astype('float64')

df1["NDEstadoVital"] = np.where(df1['NDEstadoVital']== 'VIVO',0,1)
df1["NDEstadoVital"]= df1["NDEstadoVital"].astype('float64')


df1["ServicioMayorComplejidad"] = np.where(df1['ServicioMayorComplejidad']== 'Hospitalizado',1,0)
df1["ServicioMayorComplejidad"]= df1["ServicioMayorComplejidad"].astype('float64')


correlation_mat = df1.corr()
mask = np.zeros_like(correlation_mat)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
    f, ax = plt.subplots(figsize=(13,6))
    ax = sns.heatmap(correlation_mat,
mask=mask,annot=True)
In [97]:
# Sacamos las personas unicas
df_unicos = df.drop_duplicates(subset=['PersonaBasicaID'])

Variable Sexo¶

In [98]:
tabla_freq=(pd.crosstab(index=df_unicos["Sexo"],columns="count")).reset_index()
tabla_freq['Freq. Rel.']=tabla_freq['count']/sum(tabla_freq['count'])
tabla_freq.rename(columns={'count':'Freq. Abs.'},inplace=True)
tabla_freq=tabla_freq.sort_values(by='Freq. Abs.',ascending=False).reset_index(drop=True)
tabla_freq
Out[98]:
col_0 Sexo Freq. Abs. Freq. Rel.
0 FEMENINO 268531 0.54
1 MASCULINO 231003 0.46
2 NO DEFINIDO 202 0.00
3 INDEFINIDO 1 0.00
In [99]:
fig_cont_fr = plt.figure()
ax = fig_cont_fr.add_axes([0,0,1,1])
ax.bar(tabla_freq['Sexo'],tabla_freq['Freq. Rel.']*100,color='lightskyblue')
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%')
ax.yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
ax.set(ylim=(0, 65))
plt.title("Distribucion del sexo de las personas vacunadas por Municipio")
plt.ylabel('Frecuencia Relativa')
plt.xlabel('Sexo')
plt.show()

Variable Municipio de aplicación¶

In [100]:
tabla_freq=(pd.crosstab(index=df_unicos["DescripcionMunicipio"],columns="count")).reset_index()
tabla_freq['Freq. Rel.']=tabla_freq['count']/sum(tabla_freq['count'])
tabla_freq.rename(columns={'count':'Freq. Abs.'},inplace=True)
tabla_freq=tabla_freq.sort_values(by='Freq. Abs.',ascending=False).reset_index(drop=True)
tabla_freq
Out[100]:
col_0 DescripcionMunicipio Freq. Abs. Freq. Rel.
0 Bogotá, D.C. 297325 0.59
1 Medellín 108631 0.22
2 Cali 77804 0.16
3 Montería 16240 0.03
In [101]:
fig_torta = plt.figure()
ax = fig_torta.add_axes([0,0,1,1])
plt.pie(tabla_freq["Freq. Rel."], labels=tabla_freq["DescripcionMunicipio"],autopct='%1.1f%%',startangle=90)
plt.show()

Variable Biológico¶

En este caso vamos a estandarizar los nombres de los biológicos para no tener tantas categorias.

Ver Codigo sin usar clase transform

In [102]:
#Transformador personalizado que extrae columnas pasadas como argumento a su constructor

class BiologicoTransformer():

    #Class Constructor

    def __init__(self, feature_names):
        self._feature_names = feature_names

    #Return self nada más que hacer aquí

    def fit(self, X, y = None):
        return self

    #Método que describe lo que necesitamos que haga este transformador

    def transform(self, X, y = None ):

        def map_values(val):
            if val in ['SINOVAC PARTICULAR']:
              return 'SINOVAC'
            elif val in ['PFIZER PARTICULAR']:
              return 'PFIZER'
            elif val in ['JANSSEN PARTICULAR']:
              return 'JANSSEN'
            elif val in ['MODERNA PARTICULAR']:
              return 'MODERNA'
            elif val in ['ASTRAZENECA PARTICULAR']:
              return 'ASTRAZENECA'
            else:
              return val

        X_ = X.copy()
        X_[self._feature_names] = X_[self._feature_names].apply(map_values)

        return  X_
In [103]:
pipeline1 = Pipeline(steps=[("CT", BiologicoTransformer("Biológico"))])
result = pipeline1.fit_transform(df)
result['Biológico'].value_counts()
Out[103]:
PFIZER         387662
SINOVAC        301491
MODERNA        181126
ASTRAZENECA    178781
JANSSEN         85423
Name: Biológico, dtype: int64
In [104]:
tabla_freq=(pd.crosstab(index=result["Biológico"],columns="count")).reset_index()
tabla_freq['Freq. Rel.']=tabla_freq['count']/sum(tabla_freq['count'])
tabla_freq.rename(columns={'count':'Freq. Abs.'},inplace=True)
tabla_freq=tabla_freq.sort_values(by='Freq. Abs.',ascending=False).reset_index(drop=True)
tabla_freq
Out[104]:
col_0 Biológico Freq. Abs. Freq. Rel.
0 PFIZER 387662 0.34
1 SINOVAC 301491 0.27
2 MODERNA 181126 0.16
3 ASTRAZENECA 178781 0.16
4 JANSSEN 85423 0.08
In [105]:
fig_cont_fr = plt.figure()
ax = fig_cont_fr.add_axes([0,0,1,1])
ax.bar(tabla_freq['Biológico'],tabla_freq['Freq. Rel.']*100,color='lightskyblue')
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%')
ax.yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
ax.set(ylim=(0, 40))
plt.title("Distribucion de los biológicos aplicados")
plt.ylabel('Frecuencia Relativa')
plt.xlabel('Biológico')
plt.show()

Analisis Multivariado para Biologico¶

In [106]:
df_revision_biologico = result
sns.set(style="whitegrid")  # Configuración opcional de estilo
sns.countplot(x="Biológico", hue='Confirmado', data=df_revision_biologico)
Out[106]:
<Axes: xlabel='Biológico', ylabel='count'>

Variable Número de dosis¶

Al igual como se hizo con la variable Biológico, vamos a cambiar los nombres de las dosis para entender cuales son.

Ver Codigo sin usar clase transform

In [107]:
#Transformador personalizado que extrae columnas pasadas como argumento a su constructor

class DosisTransformer():

    #Class Constructor

    def __init__(self, feature_names):
        self._feature_names = feature_names

    #Return self nada más que hacer aquí

    def fit(self, X, y = None):
        return self

    #Método que describe lo que necesitamos que haga este transformador

    def transform(self, X, y = None ):

        def map_values(val):
            if val == 1:
              return 'Primera Dosis'
            elif val == 2:
              return 'Segunda Dosis'
            elif val == 0:
              return 'Unica Dosis'
            elif val == -1:
              return 'Primer Refuerzo'
            elif val == -2:
              return 'Segundo Refuerzo'
            else:
              return val

        X_ = X.copy()
        X_[self._feature_names] = X_[self._feature_names].apply(map_values)

        return  X_
In [108]:
pipeline1 = Pipeline(steps=[("CT", DosisTransformer("NumDosis"))])
result = pipeline1.fit_transform(df)
result['NumDosis'].value_counts()
Out[108]:
Primera Dosis       440493
Segunda Dosis       388224
Primer Refuerzo     204079
Unica Dosis          63872
Segundo Refuerzo     37815
Name: NumDosis, dtype: int64
In [109]:
tabla_freq=(pd.crosstab(index=result["NumDosis"],columns="count")).reset_index()
tabla_freq['Freq. Rel.']=tabla_freq['count']/sum(tabla_freq['count'])
tabla_freq.rename(columns={'count':'Freq. Abs.'},inplace=True)
tabla_freq=tabla_freq.sort_values(by='Freq. Abs.',ascending=False).reset_index(drop=True)
tabla_freq
Out[109]:
col_0 NumDosis Freq. Abs. Freq. Rel.
0 Primera Dosis 440493 0.39
1 Segunda Dosis 388224 0.34
2 Primer Refuerzo 204079 0.18
3 Unica Dosis 63872 0.06
4 Segundo Refuerzo 37815 0.03
In [110]:
fig_cont_fr = plt.figure()
ax = fig_cont_fr.add_axes([0,0,1,1])
ax.bar(tabla_freq['NumDosis'],tabla_freq['Freq. Rel.']*100,color='lightskyblue')
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%')
ax.yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
ax.set(ylim=(0, 45))
plt.title("Distribucion de las dosis aplicadas")
plt.ylabel('Frecuencia Relativa')
plt.xlabel('Dosis')
plt.show()

Analisis Multivariado para NumDosis¶

In [111]:
df_revision = result
order = ['Primera Dosis', 'Segunda Dosis', 'Unica Dosis','Primer Refuerzo','Segundo Refuerzo']  # Reemplaza con tus categorías reales

sns.set(style="whitegrid")  # Configuración opcional de estilo
sns.countplot(x="NumDosis", hue='Confirmado', data=result,order=order)
Out[111]:
<Axes: xlabel='NumDosis', ylabel='count'>
In [112]:
# se puede ver que aunque se tienen hasta segunda dosis o refuerzos, se siguen presentando casos confirmados, con tendencia hacia la baja

Variable Comorbilidades¶

Variables que nos indican las comorbilidades

In [113]:
tabla_freq1=(pd.crosstab(index=df_unicos["CAC_VIH"],columns="count")).reset_index()
tabla_freq1['Freq. Rel.']=tabla_freq1['count']/sum(tabla_freq1['count'])

tabla_freq2=(pd.crosstab(index=df_unicos["CAC_HTA"],columns="count")).reset_index()
tabla_freq2['Freq. Rel.']=tabla_freq2['count']/sum(tabla_freq1['count'])

tabla_freq3=(pd.crosstab(index=df_unicos["CAC_Diabetes"],columns="count")).reset_index()
tabla_freq3['Freq. Rel.']=tabla_freq3['count']/sum(tabla_freq1['count'])

tabla_freq4=(pd.crosstab(index=df_unicos["CAC_PEH"],columns="count")).reset_index()
tabla_freq4['Freq. Rel.']=tabla_freq4['count']/sum(tabla_freq1['count'])

tabla_freq5=(pd.crosstab(index=df_unicos["CAC_Cancer"],columns="count")).reset_index()
tabla_freq5['Freq. Rel.']=tabla_freq5['count']/sum(tabla_freq1['count'])

tabla_freq6=(pd.crosstab(index=df_unicos["CAC_Artritis"],columns="count")).reset_index()
tabla_freq6['Freq. Rel.']=tabla_freq6['count']/sum(tabla_freq1['count'])
In [114]:
fig, axs = plt.subplots(2, 3, figsize=(14, 10))
# fig.set_size_inches(15, 5)
fig.subplots_adjust(wspace=0.3)

barr1 = axs[0][0].bar(tabla_freq1["CAC_VIH"],tabla_freq1['Freq. Rel.']*100,color='lightskyblue')
axs[0][0].bar_label(barr1,label_type='edge',fmt='%.2f%%')
axs[0][0].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[0][0].set(ylim=(0, 110))
axs[0][0].set_title('VIH')


barr2 = axs[0][1].bar(tabla_freq2["CAC_HTA"],tabla_freq2['Freq. Rel.']*100,color='lightskyblue')
axs[0][1].bar_label(barr2, label_type='edge',fmt='%.2f%%')
axs[0][1].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[0][1].set(ylim=(0, 110))
axs[0][1].set_title('Hipertensión Arterial')


barr3 = axs[0][2].bar(tabla_freq3["CAC_Diabetes"],tabla_freq3['Freq. Rel.']*100,color='lightskyblue')
axs[0][2].bar_label(barr3, label_type='edge',fmt='%.2f%%')
axs[0][2].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[0][2].set(ylim=(0, 110))
axs[0][2].set_title('Diabetes')


barr4 = axs[1][0].bar(tabla_freq4["CAC_PEH"],tabla_freq4['Freq. Rel.']*100,color='lightskyblue')
axs[1][0].bar_label(barr4, label_type='edge',fmt='%.2f%%')
axs[1][0].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[1][0].set(ylim=(0, 110))
axs[1][0].set_title('Enfermedades Huerfanas')


barr5 = axs[1][1].bar(tabla_freq5["CAC_Cancer"],tabla_freq5['Freq. Rel.']*100,color='lightskyblue')
axs[1][1].bar_label(barr5, label_type='edge',fmt='%.2f%%')
axs[1][1].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[1][1].set(ylim=(0, 110))
axs[1][1].set_title('Cáncer')


barr6 = axs[1][2].bar(tabla_freq6["CAC_Artritis"],tabla_freq6['Freq. Rel.']*100,color='lightskyblue')
axs[1][2].bar_label(barr6, label_type='edge',fmt='%.2f%%')
axs[1][2].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[1][2].set(ylim=(0, 110))
axs[1][2].set_title('Artritis')

plt.show()

Analisis Multivariado¶

In [115]:
df_revision['NumDosis'].value_counts()
Out[115]:
Primera Dosis       440493
Segunda Dosis       388224
Primer Refuerzo     204079
Unica Dosis          63872
Segundo Refuerzo     37815
Name: NumDosis, dtype: int64
In [116]:
df_revision['Confirmado'].value_counts()
Out[116]:
0    864946
1    269537
Name: Confirmado, dtype: int64
In [117]:
#datos de solo la segunda dosis y casos confirmados
df_segunda_dosis_confirmados = df_revision[(df_revision['NumDosis'] == 'Segunda Dosis') & (df_revision['Confirmado'] == 1)]

# comorbilidades
caracteristicas = ["CAC_VIH", "CAC_HTA", "CAC_Diabetes", "CAC_PEH", "CAC_Cancer", "CAC_Artritis"]

resultados = pd.DataFrame()

# Calcula el número de casos confirmados para cada característica
for caracteristica in caracteristicas:
    casos_confirmados = df_segunda_dosis_confirmados[df_segunda_dosis_confirmados[caracteristica] == 1].shape[0]
    resultados.loc[0, caracteristica] = casos_confirmados

sns.set(rc={'figure.figsize': (10, 6)})
resultados = resultados.T
resultados.plot(kind='bar', stacked=True)
plt.title("Características vs. Confirmados (Segunda Dosis)")
plt.xlabel("Características de Comorbilidad")
plt.ylabel("Número de Confirmados")
plt.legend(title="Confirmado", labels=["Sí"])
plt.show()

Los pacientes con HTA y Diabetes son aquellos que aun vacunados han tenido casos de reinfeccion aun teniendo una segunda dosis.

Variable Desenlaces¶

Variables referentes a los descenlaces clinicos

In [118]:
df_unicos['Confirmado'] = np.where(df_unicos['Confirmado'] == 1, 'Positivo' , 'No')
df['Confirmado'] = np.where(df['Confirmado'] == 1, 'Positivo' , 'No')
df_unicos['Confirmado'].value_counts()
Out[118]:
No          390984
Positivo    109016
Name: Confirmado, dtype: int64
In [119]:
df_unicos['ServicioMayorComplejidad'] = np.where(df_unicos['FechaIngresoServicioMayorComplejidad'] == pd.Timestamp('1900-01-01'), 'No' , 'Hospitalizado')
df['ServicioMayorComplejidad'] = np.where(df['FechaIngresoServicioMayorComplejidad'] == pd.Timestamp('1900-01-01'), 'No' , 'Hospitalizado')
df_unicos['ServicioMayorComplejidad'].value_counts()
Out[119]:
No               444603
Hospitalizado     55397
Name: ServicioMayorComplejidad, dtype: int64
In [120]:
tabla_freq1=(pd.crosstab(index=df_unicos["Confirmado"],columns="count")).reset_index()
tabla_freq1['Freq. Rel.']=tabla_freq1['count']/sum(tabla_freq1['count'])

tabla_freq2=(pd.crosstab(index=df_unicos["ServicioMayorComplejidad"],columns="count")).reset_index()
tabla_freq2['Freq. Rel.']=tabla_freq2['count']/sum(tabla_freq1['count'])

tabla_freq3=(pd.crosstab(index=df_unicos["NDEstadoVital"],columns="count")).reset_index()
tabla_freq3['Freq. Rel.']=tabla_freq3['count']/sum(tabla_freq1['count'])
In [121]:
fig, axs = plt.subplots(1, 3, figsize=(14, 4))
# fig.set_size_inches(15, 5)
fig.subplots_adjust(wspace=0.3)

barr1 = axs[0].bar(tabla_freq1["Confirmado"],tabla_freq1['Freq. Rel.']*100,color='lightskyblue')
axs[0].bar_label(barr1,label_type='edge',fmt='%.2f%%')
axs[0].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[0].set(ylim=(0, 110))
axs[0].set_title('Confirmado')


barr2 = axs[1].bar(tabla_freq2["ServicioMayorComplejidad"],tabla_freq2['Freq. Rel.']*100,color='lightskyblue')
axs[1].bar_label(barr2, label_type='edge',fmt='%.2f%%')
axs[1].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[1].set(ylim=(0, 110))
axs[1].set_title('Hospitalización')


barr3 = axs[2].bar(tabla_freq3["NDEstadoVital"],tabla_freq3['Freq. Rel.']*100,color='lightskyblue')
axs[2].bar_label(barr3, label_type='edge',fmt='%.2f%%')
axs[2].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[2].set(ylim=(0, 110))
axs[2].set_title('Muerte')

plt.show()

Variable Afiliacion y Regimen¶

Variables estado de afiliación y regimen

In [122]:
tabla_freq1=(pd.crosstab(index=df_unicos["EstadoAfiliacion"],columns="count")).reset_index()
tabla_freq1['Freq. Rel.']=tabla_freq1['count']/sum(tabla_freq1['count'])

tabla_freq2=(pd.crosstab(index=df_unicos["Regimen"],columns="count")).reset_index()
tabla_freq2['Freq. Rel.']=tabla_freq2['count']/sum(tabla_freq1['count'])
In [123]:
fig, axs = plt.subplots(1, 2, figsize=(14, 4))
# fig.set_size_inches(15, 5)
fig.subplots_adjust(wspace=0.3)

barr1 = axs[0].bar(tabla_freq1["EstadoAfiliacion"],tabla_freq1['Freq. Rel.']*100,color='lightskyblue')
axs[0].bar_label(barr1,label_type='edge',fmt='%.2f%%',)
axs[0].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[0].set(ylim=(0, 110))
axs[0].set_title('Estado de Afiliacion')
axs[0].tick_params(axis='x', rotation=45)

barr2 = axs[1].bar(tabla_freq2["Regimen"],tabla_freq2['Freq. Rel.']*100,color='lightskyblue')
axs[1].bar_label(barr2, label_type='edge',fmt='%.2f%%')
axs[1].yaxis.set_major_formatter(mtick.PercentFormatter(xmax=100))
axs[1].set(ylim=(0, 110))
axs[1].set_title('Régimen')


plt.show()

Análisis de outliers¶

Descripcion de outliers (Valores atipicos) dentro del conjunto de datos, es decir, que esten significativamente alejandos del rango esperado de valores.

In [124]:
#Validamos las caracteristicas estadisticas de las columnas numericas para detrminar valores minimos (negativos) o maximos (positivos)
df.select_dtypes(include=['number']).describe()
Out[124]:
PersonaBasicaID Edad NumDosis CAC_VIH CAC_HTA CAC_Diabetes CAC_PEH CAC_Cancer CAC_Artritis EdadAplicacion CodigoDepartamento CodigoMunicipio
count 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00 1,134,483.00
mean 55,942,567.09 44.91 0.83 0.00 0.15 0.05 0.00 0.01 0.00 43.49 19.75 19,748.54
std 43,540,300.43 20.12 1.18 0.07 0.35 0.21 0.04 0.10 0.06 19.99 23.63 23,630.65
min 2.00 2.00 -2.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00 5.00 5,001.00
25% 20,773,274.50 29.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.00 11.00 11,001.00
50% 41,547,199.00 44.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 42.00 11.00 11,001.00
75% 100,005,058.00 60.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 59.00 11.00 11,001.00
max 146,087,548.00 198.00 2.00 1.00 1.00 1.00 1.00 1.00 1.00 121.00 76.00 76,001.00

Se puede ver que hay valores atipicos en edad y edadaplicacion (columna calculada con la fecha de nacimiento promedio y la fecha de aplicacion del biologico, 198 cuando la media es 44 y 121 cuando la media es 49, para el caso de los codigos de departamento ,municipio y personabasicaid no se consideran para el analisis, dada su naturaleza

In [125]:
#graficamos
fig = px.histogram(df,x='Edad',nbins=30)
fig.show()
In [126]:
print(f"Skewness: {df['Edad'].skew()}")
print(f"Kurtosis: {df['Edad'].kurt()}")
Skewness: 0.19300793224563942
Kurtosis: -0.5401157740589331
In [127]:
# Asimetria positiva (SK 0.19)
# Platykurtic
In [128]:
#graficamos
#fig = px.box(df, y='Edad', title='Distribucion de edades')
#fig.show()
fig = sp.make_subplots(rows=1, cols=2, shared_yaxes=True, subplot_titles=['Edad', 'EdadAplicacion(calculada)'])
fig.add_trace(px.box(df, y='Edad').data[0], row=1, col=1)
fig.add_trace(px.box(df, y='EdadAplicacion').data[0], row=1, col=2)
fig.update_layout(title='Comparación de Columnas de Edades')
fig.show()
In [129]:
#funcion para encontrar IQR (rango intercuartil)
def find_outlier_IQR(df):
    q1=df.quantile(0.25)
    q3=df.quantile(0.75)
    IQR = q3-q1
    print(f'Q1: {q1}, Q3: {q3}, IQR: {IQR}')
    outliers = df[ ((df<(q1-1.5*IQR)) | (df>(q3+1.5*IQR))) ]
    return outliers
In [130]:
#Revisamos los Rangos intercuartiles de las columnas EDAD y EDAD_APLICACION
outliers = find_outlier_IQR(df['Edad'])
print(f'EDAD\nnúmero de outliers: '+ str(len(outliers)))
print('min valor outlier: ' + str(outliers.min()))
print('max valor outlier: ' + str(outliers.max()))

outliers = find_outlier_IQR(df['EdadAplicacion'])
print(f'EDAD_APLICACION\nnúmero de outliers: '+ str(len(outliers)))
print('min valor outlier: ' + str(outliers.min()))
print('max valor outlier: ' + str(outliers.max()))
Q1: 29.0, Q3: 60.0, IQR: 31.0
EDAD
número de outliers: 73
min valor outlier: 107
max valor outlier: 198
Q1: 28.0, Q3: 59.0, IQR: 31.0
EDAD_APLICACION
número de outliers: 5
min valor outlier: 106
max valor outlier: 121

Se podria hacer imputacion de outliers, reemplazando con la edad media para valores mayores o menors que los outliers limite definido

VER CODIGO (doble click)

En este caso lo que haremos sera borrar esos outliers <!-- def impute_outliers_IQR(df): q1=df.quantile(0.25) q3=df.quantile(0.75) IQR=q3-q1 upper = df[~(df>(q3+1.5IQR))].max() lower = df[~(df<(q1-1.5IQR))].min()

df = np.where(df > upper, # donde sea mayor df.mean(), # colocamos la media np.where( # en otros caso: df < lower, # Cuando sea menor a lower df.mean(), # colocamos la media df # el resto de las veces dejamos el valor como estaba ) ) return df

df['EdadAplicacion'] = impute_outliers_IQR(df['EdadAplicacion']) df['Edad'] = impute_outliers_IQR(df['Edad']) df.describe()['EdadAplicacion'] -->

In [131]:
def remove_outliers_IQR(df, column): #Procedimiento para limpiar outliers
    q1 = df[column].quantile(0.25)
    q3 = df[column].quantile(0.75)
    IQR = q3 - q1

    lower_bound = q1 - 1.5 * IQR
    upper_bound = q3 + 1.5 * IQR
    print(df[(df[column] < lower_bound) | (df[column] > upper_bound)].index)
    df.drop(df[(df[column] < lower_bound) | (df[column] > upper_bound)].index, inplace=True)
In [132]:
remove_outliers_IQR(df, 'Edad')
Int64Index([ 105181,  506228,  506229,  518722,  518723,  518724,  518725,
             520918,  524624,  524625,  524626,  534182,  534183,  538607,
             538608,  544322,  554794,  554795,  564308,  564309,  578002,
             583700,  584612,  593773,  603604,  603605,  611080,  615331,
             615332,  616422,  616969,  616970,  617754,  617755,  625248,
             631949,  631950,  636193,  636194,  653497,  653498,  679766,
             697966,  697967,  697968,  706401,  706402,  727441,  727442,
             755423,  755424,  789710,  972153,  978008,  978009,  995359,
            1004685, 1012996, 1018821, 1034174, 1071722, 1071723, 1084619,
            1084620, 1089720, 1089721, 1106619, 1106620, 1121892, 1121893,
            1127742, 1127743, 1133471],
           dtype='int64')
In [133]:
fig = sp.make_subplots(rows=1, cols=2, shared_yaxes=True, subplot_titles=['Edad', 'EdadAplicacion(calculada)'])
fig.add_trace(px.box(df, y='Edad').data[0], row=1, col=1)
fig.add_trace(px.box(df, y='EdadAplicacion').data[0], row=1, col=2)
fig.update_layout(title='Comparación de Columnas de Edades')
fig.show()
In [134]:
#graficamos
fig = px.histogram(df,x='Edad',nbins=30)
fig.show()
In [135]:
print(f"Skewness: {df['Edad'].skew()}")
print(f"Kurtosis: {df['Edad'].kurt()}")
Skewness: 0.16871097875694618
Kurtosis: -0.7255114503193738
In [136]:
# Asimetria positiva (SK 0.16)
# platicúrtica

Conclusiones Outliers¶

Para el caso de las columnas Edad y EdadAplicacion, se realizo una limpieza de los registros completos que tenian valroes atipicos en las columnas edades, quedado con un total de 113441, es decir, se borraron 73 registros basado en la columna Edad y no la columna EdadCalculda, nota imporante, sería interesante entender la naturaleza de estos outliers.

In [137]:
correlation_mat = df.corr()
mask = np.zeros_like(correlation_mat)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
    f, ax = plt.subplots(figsize=(13,6))
    ax = sns.heatmap(correlation_mat,
mask=mask,annot=True,cmap="YlGnBu")
In [138]:
df_resd = df.copy()
df_resd.plot(kind='box', subplots=True, layout=(4,4), sharex=False, sharey=False, figsize=(15,15), title='Box Plot para las variables de entrada')
#plt.savefig('vino')
plt.show()
In [139]:
#sns.pairplot(df)

Limpieza de Datos¶

In [140]:
df['Sexo'].unique()
Out[140]:
array(['MASCULINO', 'FEMENINO', nan, 'NO DEFINIDO', 'INDEFINIDO'],
      dtype=object)
In [141]:
valores_nulos_por_columna = df.isna().sum()
columnas_con_valores_no_nulos = valores_nulos_por_columna[valores_nulos_por_columna != 0]
print(columnas_con_valores_no_nulos)
Sexo    488
dtype: int64

Estandarización¶

Estandarizamos No definido e Indefinido por Indefinido

In [142]:
df["Sexo"] = df["Sexo"].str.replace('NO DEFINIDO', 'INDEFINIDO')

Para un mejor entendimiento se va a observar graficamente:

In [143]:
(df.value_counts('Sexo',normalize=True)*100).round(2).astype(str)+'%'
Out[143]:
Sexo
FEMENINO      54.51%
MASCULINO     45.47%
INDEFINIDO     0.03%
dtype: object

Imputación¶

Puesto que tenemos valores faltantes en las columnas de Sexo, seleccionaremos de manera aleatoria un valor entre los existentes para hacer la asignacion

In [144]:
df['Sexo'].unique()
Out[144]:
array(['MASCULINO', 'FEMENINO', nan, 'INDEFINIDO'], dtype=object)
In [145]:
# Calcula la distribución de los valores existentes en la columna 'Sexo'
sexo_distribution = df['Sexo'].value_counts(normalize=True)

# Imputa los valores NaN en función de la distribución
df['Sexo'].fillna(pd.Series(np.random.choice(sexo_distribution.index, p=sexo_distribution.values, size=len(df))), inplace=True)

# Verifica que los valores NaN se hayan reemplazado correctamente
print(df['Sexo'].unique())
['MASCULINO' 'FEMENINO' 'INDEFINIDO']
In [146]:
#Sexo
#FEMENINO       618081
#INDEFINIDO        291
#MASCULINO      515550
#Name: Sexo, dtype: int64

df['Sexo'].groupby(df['Sexo']).count()
Out[146]:
Sexo
FEMENINO      618351
INDEFINIDO       291
MASCULINO     515768
Name: Sexo, dtype: int64
In [147]:
(df.value_counts('Sexo',normalize=True)*100).round(2).astype(str)+'%'
Out[147]:
Sexo
FEMENINO      54.51%
MASCULINO     45.47%
INDEFINIDO     0.03%
dtype: object

Analisis Estadistico¶

Analisis 1¶

Existe relación entre la edad de las personas vacunadas y su desenlace (Confirmado, Hospitalizado, Muerto)? Cualitativa y Cuantitativa

Confirmado¶

In [148]:
# Crear una figura con tres subplots en una fila
fig, axes = plt.subplots(1, 3, figsize=(18, 4))

# Crear el gráfico de cajas y bigotes en el primer subplot
sns.boxplot(x=df["Confirmado"], y=df["EdadAplicacion"], palette='rocket_r', ax=axes[0])
axes[0].set_ylabel('Edades')
axes[0].set_xlabel('')
axes[0].set_title('Casos Confirmados')

# Filtrar datos para cada caja
df_confirmado_si = df[df["Confirmado"] == "Positivo"]
df_confirmado_no = df[df["Confirmado"] == "No"]

# Crear gráfico de barras para Confirmado "Si" en el segundo subplot
sns.histplot(data=df_confirmado_si, x='EdadAplicacion', color='blue', bins=20, ax=axes[1])
axes[1].set_xlabel('Edades')
axes[1].set_ylabel('Frecuencia')
axes[1].set_title('Hist POSITIVO')

# Crear gráfico de barras para Confirmado "No" en el tercer subplot
sns.histplot(data=df_confirmado_no, x='EdadAplicacion', color='red', bins=20, ax=axes[2])
axes[2].set_xlabel('Edades')
axes[2].set_ylabel('Frecuencia')
axes[2].set_title('Hist NO')

# Ajustar espaciado entre subplots
plt.tight_layout()

# Mostrar la figura con los tres gráficos en una fila
plt.show()

Validación de los supuestos (NORMALIDAD)

Verifiquemos primero el supuesto de normalidad. El supuesto establece que las poblaciones deben seguir la distribución normal o tener un tamaño mayor a 30 para que se cumpla el TLC.

Recordemos las hipótesis:

Ho: La muestra proviene de una población que sigue una distribución normal

Ha: La muestra NO proviene de una población que sigue una distribución normal

In [149]:
## QQplots
fig, axs = plt.subplots(ncols=2)
fig.set_size_inches(8, 4)
fig.subplots_adjust(wspace=0.3)

ax1=qqplot(df[df["Confirmado"]=="Positivo"]["EdadAplicacion"], line='s',ax=axs[0])
axs[0].set_title('Positivo')
ax2=qqplot(df[df["Confirmado"]=="No"]["EdadAplicacion"], line='s',ax=axs[1])
axs[1].set_title('No')

plt.show()
In [150]:
# normalidad
print("Población: Confirmado Positivo")
Estad,vp = shapiro(df[df["Confirmado"]=="Positivo"]["Edad"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["Confirmado"]=="Positivo"]["Edad"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')

print('')

print("Población: No Confirmado positivo ")
Estad,vp = shapiro(df[df["Confirmado"]=="No"]["Edad"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["Confirmado"]=="No"]["Edad"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')
Población: Confirmado Positivo
Estadístico SW= 0.9806710481643677, Valor-p= 0.0
Estadístico AD= 1803.0124239556608, Valor crítico (sign. 5%)= 0.787

Población: No Confirmado positivo 
Estadístico SW= 0.985482931137085, Valor-p= 0.0
Estadístico AD= 4039.2869605114684, Valor crítico (sign. 5%)= 0.787
In [151]:
## distribucion de confirmdos y no confirmados para evaluar la media de ambas

Conclusión: La distribucion o proviene de una dist normal

Validación de los supuestos (HOMOGENEIDAD DE VARIANZAS)

Ahora pasemos al supuesto de homogeneidad de varianzas y recordemos las hipótesis:

Ho: La varianza en todas las poblaciones es igual

Ha: La varianza de al menos 1 es diferente

In [152]:
# Homogeneidad de varianzas
Estad,vp=levene(df_unicos[df_unicos["Confirmado"]=="Positivo"]["EdadAplicacion"],
                df_unicos[df_unicos["Confirmado"]=="No"]["EdadAplicacion"],
                center='mean')
print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 7592.293172863293, Valor-p= 0.0

Conclusión: no hay homogenidad de varianzas

Prueba no parametrica

h0 : La distribucion de ambas poblaciones es la misma (misma mediana)

ha : La distribucion de ambas poblaciones es diferente (diferente mediana)

In [153]:
Estad,vp=mannwhitneyu(df_unicos[df_unicos["Confirmado"]=="Positivo"]["EdadAplicacion"],
                   df_unicos[df_unicos["Confirmado"]=="No"]["EdadAplicacion"])

print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 22637133770.5, Valor-p= 3.740289196574841e-217

Conclusion : como el valor p es menor que la significancia rechazo Ha

Hospitalizado¶

In [154]:
# Crear una figura con tres subplots en una fila
fig, axes = plt.subplots(1, 3, figsize=(18, 4))

# Crear el gráfico de cajas y bigotes en el primer subplot
sns.boxplot(x=df["ServicioMayorComplejidad"], y=df["EdadAplicacion"], palette='rocket_r', ax=axes[0])
axes[0].set_ylabel('Edades')
axes[0].set_xlabel('')
axes[0].set_title('Hospitalizaciones')

# Filtrar datos para cada caja
df_hospitalizado = df[df['ServicioMayorComplejidad'] == 'Hospitalizado']
df_no = df[df['ServicioMayorComplejidad'] == 'No']

# Crear gráfico de barras para Confirmado "Si" en el segundo subplot
sns.histplot(data=df_hospitalizado, x='EdadAplicacion', color='blue', bins=20, ax=axes[1])
axes[1].set_xlabel('Edades')
axes[1].set_ylabel('Frecuencia')
axes[1].set_title('Hist HOSPITALIZADO')

# Crear gráfico de barras para Confirmado "No" en el tercer subplot
sns.histplot(data=df_no, x='EdadAplicacion', color='red', bins=20, ax=axes[2])
axes[2].set_xlabel('Edades')
axes[2].set_ylabel('Frecuencia')
axes[2].set_title('Hist NO')

# Ajustar espaciado entre subplots
plt.tight_layout()

# Mostrar la figura con los tres gráficos en una fila
plt.show()

Validación de los supuestos (NORMALIDAD)

Verifiquemos primero el supuesto de normalidad. El supuesto establece que las poblaciones deben seguir la distribución normal o tener un tamaño mayor a 30 para que se cumpla el TLC.

Recordemos las hipótesis:

Ho: La muestra proviene de una población que sigue una distribución normal

Ha: La muestra NO proviene de una población que sigue una distribución normal

In [155]:
## QQplots
fig, axs = plt.subplots(ncols=2)
fig.set_size_inches(8, 4)
fig.subplots_adjust(wspace=0.3)

ax1=qqplot(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"], line='s',ax=axs[0])
axs[0].set_title('Hospitalizado')
ax2=qqplot(df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"], line='s',ax=axs[1])
axs[1].set_title('No')

plt.show()
In [156]:
# normalidad
print("Población: Hospitalizado")
Estad,vp = shapiro(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')

print('')

print("Población: No Hospitalizado")
Estad,vp = shapiro(df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')
Población: Hospitalizado
Estadístico SW= 0.9816091060638428, Valor-p= 0.0
Estadístico AD= 837.409109200089, Valor crítico (sign. 5%)= 0.787

Población: No Hospitalizado
Estadístico SW= 0.9861602783203125, Valor-p= 0.0
Estadístico AD= 4321.834139822866, Valor crítico (sign. 5%)= 0.787

Conclusión: no hay normalidad

Validación de los supuestos (HOMOGENEIDAD DE VARIANZAS)

Ahora pasemos al supuesto de homogeneidad de varianzas y recordemos las hipótesis:

Ho: La varianza en todas las poblaciones es igual

Ha: La varianza de al menos 1 es diferente

In [157]:
# Homogeneidad de varianzas
Estad,vp=levene(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"],
                df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"],
                center='mean')
print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 6599.015596648111, Valor-p= 0.0
In [ ]:
 
In [158]:
Estad,vp=ttest_ind(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"],
                   df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"],
                   equal_var=False)

print(f'Media grupo 1:{round(df[df["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"].mean(),2)}, Media grupo 2:{round(df[df["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"].mean(),2)}, Estadístico t= {Estad}, Valor-p= {vp}')
Media grupo 1:43.67, Media grupo 2:43.46, Estadístico t= 3.925659380989586, Valor-p= 8.65238266075685e-05

Conclusion : rechazo la h0, por tanto la varianza de al menos 1 es diferente, teniendo en cuenta que valor p es 0.0007 hay diferencia significativa entre las poblaciones

In [159]:
# Mann-Whitney U

H0: No hay diferencia significativa entre los dos grupos poblacionales

Ha: Hay una diferencia significativa entre los dos grupos poblacionales (las distribuciones de ambos grupos son diferentes).

In [160]:
Estad,vp=mannwhitneyu(df_unicos[df_unicos["ServicioMayorComplejidad"]=="Hospitalizado"]["EdadAplicacion"],
                   df_unicos[df_unicos["ServicioMayorComplejidad"]=="No"]["EdadAplicacion"])

print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 13029501818.0, Valor-p= 2.85443841538703e-110

Conclusion : rechazamos la hipotesis nula, por tanto hay diferencia significativa entre los hospitalziados y no hospitizalidso

Muerte¶

In [161]:
# Crear una figura con tres subplots en una fila
fig, axes = plt.subplots(1, 3, figsize=(18, 4))

# Crear el gráfico de cajas y bigotes en el primer subplot
sns.boxplot(x=df["NDEstadoVital"], y=df["EdadAplicacion"], palette='rocket_r', ax=axes[0])
axes[0].set_ylabel('Edades')
axes[0].set_xlabel('')
axes[0].set_title('ESTADO')

# Filtrar datos para cada caja
df_si = df[df['NDEstadoVital'] == 'VIVO']
df_no = df[df['NDEstadoVital'] == 'MUERTO']

# Crear gráfico de barras para Confirmado "Si" en el segundo subplot
sns.histplot(data=df_si, x='EdadAplicacion', color='blue', bins=20, ax=axes[1])
axes[1].set_xlabel('Edades')
axes[1].set_ylabel('Frecuencia')
axes[1].set_title('Hist VIVOS')

# Crear gráfico de barras para Confirmado "No" en el tercer subplot
sns.histplot(data=df_no, x='EdadAplicacion', color='red', bins=20, ax=axes[2])
axes[2].set_xlabel('Edades')
axes[2].set_ylabel('Frecuencia')
axes[2].set_title('Hist MUERTO')

# Ajustar espaciado entre subplots
plt.tight_layout()

# Mostrar la figura con los tres gráficos en una fila
plt.show()

Validación de los supuestos (NORMALIDAD)

Verifiquemos primero el supuesto de normalidad. El supuesto establece que las poblaciones deben seguir la distribución normal o tener un tamaño mayor a 30 para que se cumpla el TLC.

Recordemos las hipótesis:

Ho: La muestra proviene de una población que sigue una distribución normal

Ha: La muestra NO proviene de una población que sigue una distribución normal

In [162]:
## QQplots
fig, axs = plt.subplots(ncols=2)
fig.set_size_inches(8, 4)
fig.subplots_adjust(wspace=0.3)

ax1=qqplot(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"], line='s',ax=axs[0])
axs[0].set_title('Fallecido')
ax2=qqplot(df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"], line='s',ax=axs[1])
axs[1].set_title('Vivo')

plt.show()
In [163]:
# normalidad
print("Población: Fallecido")
Estad,vp = shapiro(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')

print('')

print("Población: Vivo")
Estad,vp = shapiro(df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"])
print(f'Estadístico SW= {Estad}, Valor-p= {vp}')

Estad,vc,sig=anderson(df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"])
print(f'Estadístico AD= {Estad}, Valor crítico (sign. 5%)= {vc[2]}')
Población: Fallecido
Estadístico SW= 0.9159862995147705, Valor-p= 0.0
Estadístico AD= 222.8300510199515, Valor crítico (sign. 5%)= 0.787

Población: Vivo
Estadístico SW= 0.9839651584625244, Valor-p= 0.0
Estadístico AD= 4658.138550783973, Valor crítico (sign. 5%)= 0.787

Conclusion : las distribuciones no son normales, dado que el valor p es menos a la significancia

Validación de los supuestos (HOMOGENEIDAD DE VARIANZAS)

Ahora pasemos al supuesto de homogeneidad de varianzas y recordemos las hipótesis:

Ho: La varianza en todas las poblaciones es igual

Ha: La varianza de al menos 1 es diferente

In [164]:
# Homogeneidad de varianzas
Estad,vp=levene(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"],
                df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"],
                center='mean')
print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 2044.7263386218026, Valor-p= 0.0

Conclusion : Rechazo la h0, por tanto, la varianza de almenos 1 es diferente

In [165]:
Estad,vp=ttest_ind(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"],
                   df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"],
                   equal_var=False)

print(f'Media grupo 1:{round(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"].mean(),2)}, Media grupo 2:{round(df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"].mean(),2)}, Estadístico t= {Estad}, Valor-p= {vp}')
Media grupo 1:75.83, Media grupo 2:43.18, Estadístico t= 215.46345152659362, Valor-p= 0.0
In [166]:
#Dado que no hay normalidad, realizamos prueba no paramétrica de Mann-Whitney-Wilcoxon:

Estad,vp=mannwhitneyu(df[df["NDEstadoVital"]=="MUERTO"]["EdadAplicacion"],
                   df[df["NDEstadoVital"]=="VIVO"]["EdadAplicacion"])

print(f'Estadístico W= {Estad}, Valor-p= {vp}')
Estadístico W= 10688816539.0, Valor-p= 0.0

Conclusion : Rechazo la h0

Analisis 2¶

Existe relacion entre el desenlace (Confirmado, Hospitalizado, Fallecido) y el sexo de la persona vacunada?

In [167]:
df['Sexo'].unique()
Out[167]:
array(['MASCULINO', 'FEMENINO', 'INDEFINIDO'], dtype=object)
In [168]:
df['Confirmado'].unique()
Out[168]:
array(['Positivo', 'No'], dtype=object)
In [169]:
df['ServicioMayorComplejidad'].unique()
Out[169]:
array(['No', 'Hospitalizado'], dtype=object)
In [170]:
df['NDEstadoVital'].unique()
Out[170]:
array(['VIVO', 'MUERTO'], dtype=object)
In [171]:
df_selec = df[(df['Sexo']=='FEMENINO') | (df['Sexo']=='MASCULINO')]
  • Confirmados:
In [172]:
tabla_frec=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["Confirmado"],normalize="index").reset_index()
tabla_frec
Out[172]:
Confirmado Sexo No Positivo
0 FEMENINO 0.76 0.24
1 MASCULINO 0.77 0.23
In [173]:
fig_sns = plt.figure()
ax = fig_sns.add_axes([0,0,1,1])
ax=sns.barplot(x=tabla_frec["Sexo"],y=tabla_frec["Positivo"]*100,order=tabla_frec.sort_values(by='No')["Sexo"])
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%', padding=5)
ax.set(ylim=(0, 25))
plt.ylabel('Frec.Rel.')
plt.xlabel('')
plt.show()

Prueba de Chi Cuadrado de independencia

Recordemos las hipótesis:

  • Ho: No existe relación entre las variables
  • Ha: Existe relación entre las variables
In [174]:
tabla_frec_abs=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["Confirmado"])
Estad,vp,gl,frec_esp=chi2_contingency(tabla_frec_abs)
print(f'Estadístico X^2= {Estad}, Valor-p= {vp}')
Estadístico X^2= 391.26633943171714, Valor-p= 4.38727407560172e-87

Conclusion: Tenemos evidencia suficiente para determinar que existe relacion entre confirmados y el sexo (se rechaza h0)

Hospitalizados:¶

In [175]:
tabla_frec=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["ServicioMayorComplejidad"],normalize="index").reset_index()
tabla_frec
Out[175]:
ServicioMayorComplejidad Sexo Hospitalizado No
0 FEMENINO 0.12 0.88
1 MASCULINO 0.11 0.89
In [176]:
fig_sns = plt.figure()
ax = fig_sns.add_axes([0,0,1,1])
ax=sns.barplot(x=tabla_frec["Sexo"],y=tabla_frec["Hospitalizado"]*100,order=tabla_frec.sort_values(by='No')["Sexo"])
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%', padding=5)
ax.set(ylim=(0, 13))
plt.ylabel('Frec.Rel.')
plt.xlabel('')
plt.show()

Prueba de Chi Cuadrado de independencia

Recordemos las hipótesis:

  • Ho: No existe relación entre las variables
  • Ha: Existe relación entre las variables
In [177]:
tabla_frec_abs=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["ServicioMayorComplejidad"])
Estad,vp,gl,frec_esp=chi2_contingency(tabla_frec_abs)
print(f'Estadístico X^2= {Estad}, Valor-p= {vp}')
Estadístico X^2= 185.24062757437062, Valor-p= 3.4774996176279596e-42

Conclusion: Tenemos evidencia suficiente para determinar que existe relacion entre confirmados y el sexo (se rechaza h0)

Muerte¶

In [178]:
tabla_frec=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["NDEstadoVital"],normalize="index").reset_index()
tabla_frec
Out[178]:
NDEstadoVital Sexo MUERTO VIVO
0 FEMENINO 0.01 0.99
1 MASCULINO 0.01 0.99
In [179]:
fig_sns = plt.figure()
ax = fig_sns.add_axes([0,0,1,1])
ax=sns.barplot(x=tabla_frec["Sexo"],y=tabla_frec["MUERTO"]*100,order=tabla_frec.sort_values(by='VIVO')["Sexo"])
ax.bar_label(ax.containers[0], label_type='edge',fmt='%.2f%%', padding=5)
ax.set(ylim=(0, 1.25))
plt.ylabel('Frec.Rel.')
plt.xlabel('')
plt.show()

Prueba de Chi Cuadrado de independencia

Recordemos las hipótesis:

  • Ho: No existe relación entre las variables
  • Ha: Existe relación entre las variables
In [180]:
tabla_frec_abs=pd.crosstab(index=df_selec["Sexo"],columns=df_selec["NDEstadoVital"])
Estad,vp,gl,frec_esp=chi2_contingency(tabla_frec_abs)
print(f'Estadístico X^2= {Estad}, Valor-p= {vp}')
Estadístico X^2= 110.85573988448668, Valor-p= 6.363703081076376e-26

Conclusion: Tenemos evidencia suficiente para determinar que existe relacion entre estado y el sexo (se rechaza h0)